<template>
    <div class="w100 h100">
        <div :id="id"></div>
        <svg class="dn">
            <defs>
                <filter
                    x="-33.8%"
                    y="-33.8%"
                    width="167.5%"
                    height="167.5%"
                    filterUnits="objectBoundingBox"
                    id="filter-10"
                >
                    <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
                    <feGaussianBlur stdDeviation="4" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
                    <feColorMatrix
                        values="0 0 0 0 0.876105183   0 0 0 0 0.929202962   0 0 0 0 1  0 0 0 1 0"
                        type="matrix"
                        in="shadowBlurOuter1"
                    ></feColorMatrix>
                </filter>
            </defs>
        </svg>
    </div>
</template>

<script>
import Chart from '../chart.js'
import * as d3 from 'd3'

export default {
    props: {
        id: {
            required: true,
        },
        data: {
            required: true,
        },
        width: {},
        height: {},
        maxValue: {
            default: 100,
            type: Number,
        },
    },
    data() {
        return {
            oldIndex: null,
        }
    },
    mounted() {
        this.$nextTick(() => {
            setTimeout(() => {
                this.init(this.data)
            }, 500)
        })
    },
    methods: {
        init(data) {
            const me = this
            /* ----------------------------配置参数------------------------  */
            const chart = new Chart()
            const box = d3.select('#' + this.id)
            box.node().innerHTML = ''
            box.node().style.width = this.width + 'px'
            box.node().style.height = this.height + 'px'
            const config = {
                margins: { top: 20, left: 20, bottom: 20, right: 20 },
                textColor: '#535962',
                title: '基本雷达图',
                radius: (Math.min(this.width, this.height) * 4) / 11,
                animateDuration: 1000,
                tickNum: 5,
                axisfillColor: ['white', '#ddd'],
                axisStrokeColor: 'gray',
                pointsColor: 'white',
                pointsSize: 3,
            }

            chart.box(box)
            chart.margins(config.margins)

            chart.setId(this.id)
            chart.width(this.width)
            chart.height(this.height)

            /* ----------------------------尺度转换------------------------  */
            chart.scaleRadius = d3
                .scaleLinear()
                .domain([0, this.maxValue || 100])
                .range([0, config.radius])

            /* ----------------------------渲染坐标轴------------------------  */
            chart.renderAxes = function () {
                // ----渲染背景多边形-----
                const points = getPolygonPoints(data.length, config.radius, config.tickNum)

                const axes = chart
                    .body()
                    .append('g')
                    .attr('class', 'axes')
                    .attr('transform', 'translate(' + chart.getBodyWidth() / 2 + ',' + chart.getBodyHeight() / 2 + ')')
                    .selectAll('axis')
                    .data(points)

                axes.enter()
                    .append('polygon')
                    .attr('class', 'axis')
                    .merge(axes)
                    .attr('points', d => d)
                    .attr('fill', 'transparent')
                    .attr('stroke', '#F1F7FF')

                axes.exit().remove()

                // ----渲染对角线-----
                const line = d3.line()

                const outerPoints = getOuterPoints(points[0])

                const lines = d3.select('.axes').selectAll('.line').data(outerPoints)

                lines
                    .enter()
                    .append('path')
                    .attr('class', 'line')
                    .merge(lines)
                    .attr('d', d => {
                        return line([
                            [0, 0],
                            [d[0], d[1]],
                        ])
                    })
                    .attr('stroke', '#F1F7FF')

                lines.exit().remove()

                //生成背景多边形的顶点
                function getPolygonPoints(vertexNum, outerRadius, tickNum) {
                    const points = []
                    let polygon

                    if (vertexNum < 3) return points

                    const anglePiece = (Math.PI * 2) / vertexNum
                    const radiusReduce = outerRadius / tickNum

                    for (let r = outerRadius; r > 0; r -= radiusReduce) {
                        polygon = []

                        for (let i = 0; i < vertexNum; i++) {
                            polygon.push(Math.sin(i * anglePiece) * r + ',' + Math.cos(i * anglePiece) * r)
                        }

                        points.push(polygon.join(' '))
                    }

                    return points
                }

                //得到最外层多边形的顶点
                function getOuterPoints(outerPoints) {
                    const points = outerPoints.split(' ').map(d => d.split(','))
                    return points
                }
            }

            /* ----------------------------渲染文本标签------------------------  */
            chart.renderText = function () {
                const texts = d3.select('.axes').selectAll('.label').data(data)

                texts
                    .enter()
                    .append('text')
                    .attr('class', 'label')
                    .merge(texts)
                    .attr('x', (d, i) => Math.sin((i * Math.PI * 2) / data.length) * (config.radius + 20))
                    .attr('y', (d, i) => Math.cos((i * Math.PI * 2) / data.length) * (config.radius + 20))
                    .attr('text-anchor', (d, i) => computeTextAnchor(data, i))
                    .attr('dy', 6.5) //由于text-anchor属性在垂向上对齐文字底部，故需要使其对齐文字中部
                    .text(d => d.label)
                    .attr('fill', '#535962')
                    .attr('stroke', 'none')

                function computeTextAnchor(data, i) {
                    if (data.length < 3) return

                    const angle = (i * 360) / data.length

                    if (angle === 0 || Math.abs(angle - 180) < 0.01) {
                        return 'middle'
                    } else if (angle > 180) {
                        return 'end'
                    } else {
                        return 'start'
                    }
                }
            }

            /* ----------------------------渲染数据多边形------------------------  */
            chart.renderPolygons = function () {
                const newData = handleData(data)

                const polygons = chart.body().selectAll('.polygons').data(newData)

                polygons
                    .enter()
                    .append('g')
                    .attr('class', d => 'g-' + d.value)
                    .attr('transform', 'translate(' + chart.getBodyWidth() / 2 + ',' + chart.getBodyHeight() / 2 + ')')
                    .append('polygon')
                    .attr('class', 'polygon')
                    .merge(polygons)
                    .attr('fill', '#0062FF')
                    .attr('fill-opacity', '0.05')
                    .attr('stroke', '#0062FF')
                    .attr('stroke-width', '1')
                    .attr('points', (d, i) => {
                        const miniPolygon = []
                        d.forEach(() => {
                            miniPolygon.push('0,0')
                        })
                        return miniPolygon.join(' ')
                    })
                    .transition()
                    .duration(config.animateDuration)
                    .attr('points', generatePolygons)

                polygons.exit().remove()

                //处理数据，转化数据结构，方便渲染
                function handleData(data) {
                    const newData = []

                    Object.keys(data[0]).forEach(key => {
                        if (key !== 'label') {
                            const item = []
                            item.value = key
                            newData.push(item)
                        }
                    })

                    data.forEach(d => {
                        newData.forEach((item, i) => {
                            item.push([d.label, d['value']])
                        })
                    })

                    return newData
                }

                //计算多边形的顶点并生成顶点圆圈
                function generatePolygons(d, index) {
                    const points = []
                    const anglePiece = (Math.PI * 2) / d.length

                    d.forEach((item, i) => {
                        const x = Math.sin(i * anglePiece) * chart.scaleRadius(item[1])
                        const y = Math.cos(i * anglePiece) * chart.scaleRadius(item[1])

                        //添加交点圆圈
                        d3.select('.g-' + d.value)
                            .append('circle')
                            .attr('class', 'point-' + d.value)
                            .attr('fill', '#0062FF')
                            .attr('stroke', '#0062FF')
                            .attr('cx', 0)
                            .attr('cy', 0)
                            .attr('r', config.pointsSize)
                            .transition()
                            .duration(config.animateDuration)
                            .attr('cx', x)
                            .attr('cy', y)

                        points.push(x + ',' + y)
                    })

                    return points.join(' ')
                }
            }

            /* ----------------------------渲染图标题------------------------  */
            chart.renderTitle = function () {
                chart
                    .svg()
                    .append('text')
                    .classed('title', true)
                    .attr('x', chart.width() / 2)
                    .attr('y', 0)
                    .attr('dy', '2em')
                    .text(config.title)
                    .attr('fill', config.textColor)
                    .attr('text-anchor', 'middle')
                    .attr('stroke', config.textColor)
            }

            /* ----------------------------绑定鼠标交互事件------------------------  */
            chart.addMouseOn = function () {
                d3.selectAll('.polygon')
                    .on('mouseover', function (d, i) {
                        const e = d3.event
                        const position = d3.mouse(chart.svg().node())

                        d3.select(e.target).attr('stroke-width', '2')

                        chart
                            .svg()
                            .append('text')
                            .classed('tip', true)
                            .attr('x', position[0] + 5)
                            .attr('y', position[1])
                            .attr('fill', config.textColor)
                            .text('')
                    })
                    .on('mouseleave', function () {
                        const e = d3.event

                        d3.select(e.target).attr('stroke-width', '1')

                        d3.select('.tip').remove()
                    })
            }

            chart.render = function () {
                // chart.renderTitle()

                chart.renderAxes()

                chart.renderText()

                chart.renderPolygons()

                // chart.addMouseOn()
            }

            chart.renderChart()
        },
    },
}
</script>

<style lang="scss" scoped></style>
